'use strict';

const path = require('path')
const fs = require('fs')
const npminstall = require('npminstall')
const fse = require('fs-extra')
const pkgDir = require("pkg-dir").sync;
const {isObject} = require('@fobiz-cli/utils')
const formatPath = require('@fobiz-cli/format-path')
const log = require('@fobiz-cli/log')
const {getDefaultRegistry, getLatestVersion} = require('@fobiz-cli/get-npm-info')

const LATEST = 'latest'

class Package {
    constructor(options) {
        if (!options) {
            throw new Error('Package类的options参数不能为空！')
        }
        if (!isObject(options)) {
            throw new Error('Package类的options参数必须为对象！')
        }
        // package目标路径：node_modules所在的地址
        this.targetPath = options.targetPath
        // package缓存路径：包真实存在的地址
        this.storeDir = options.storeDir
        this.packageName = options.packageName
        this.packageVersion = options.packageVersion
        this.pkgCachePathPrefix = this.packageName.replace('/', '_')
    }

    get pkgCachePath() {
        return path.resolve(this.storeDir, `_${this.pkgCachePathPrefix}@${this.packageVersion}@${this.packageName}`)
    }

    async prepare() {
        if (!fs.existsSync(this.targetPath)) {
            fse.mkdirpSync(this.targetPath)
        }
        if (this.storeDir && !fs.existsSync(this.storeDir)) {
            fse.mkdirpSync(this.storeDir)
        }
        if (this.packageVersion === LATEST) {
            this.packageVersion = await getLatestVersion(this.packageName)
        }
    }

    async exists() {
        await this.prepare()
        // 如果没有指定storeDir，那么一定是指定了targetPath，也就是包的安装目录
        if (!this.storeDir) {
            return fs.existsSync(this.targetPath)
        } else {
            return fs.existsSync(this.pkgCachePath);
        }
    }

    install() {
        /**
         * @property root string 必传 指定安装的根目录，安装成功后，会在当前目录下面的node_modules中
         *  创建一个package的链接，链接到package真实的path
         * @property storeDir string 指定package真实的path，也是package的缓存路径 */
        return npminstall({
            root: this.targetPath,
            storeDir: this.storeDir,
            registry: getDefaultRegistry(),
            pkgs: [
                {
                    name: this.packageName,
                    version: this.packageVersion
                }
            ]
        })
    }

    async update() {
        await this.prepare()
        const latestVersion = await getLatestVersion(this.packageName)
        log.verbose('package latest version', latestVersion)
        if (latestVersion !== this.packageVersion) {
            await npminstall({
                root: this.targetPath,
                storeDir: this.storeDir,
                registry: getDefaultRegistry(),
                pkgs: [{
                    name: this.packageName,
                    version: latestVersion
                }]
            })
            this.packageVersion = latestVersion
        } else {
            this.packageVersion = latestVersion
        }
    }

    getEntryFilePath() {
        const _getEntryFilePath = targetPath => {
            const dir = pkgDir(targetPath)
            if (dir) {
                const pkgFile = fse.readJsonSync(path.resolve(dir, 'package.json'))
                if (pkgFile && pkgFile.main) {
                    return formatPath(path.resolve(dir, pkgFile.main))
                }
            }
        }
        if (this.storeDir) {
            return _getEntryFilePath(this.pkgCachePath)
        } else {
            return _getEntryFilePath(this.targetPath)
        }
    }
}

module.exports = Package;
